#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <iphlpapi.h>
#include <icmpapi.h>
#include <iostream>
#include <chrono>

#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")

typedef struct _IPHEADER
{
    unsigned char ip_verlen;
    unsigned char ip_tos;
    unsigned short ip_totallength;
    unsigned short ip_id;
    unsigned short ip_offset;
    unsigned char ip_ttl;
    unsigned char ip_proto;
    unsigned short ip_checksum;
    unsigned int ip_src;
    unsigned int ip_dst;
} IPHEADER;

typedef struct _ICMPHEADER
{
    unsigned char type;
    unsigned char code;
    unsigned short checksum;
    unsigned short id;
    unsigned short seq;
} ICMPHEADER;

unsigned short checksum(void *b, int len)
{
    unsigned short *buf = (unsigned short *)b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char *)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}

int main()
{
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
    {
        return 1;
    }

    SOCKET sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sock == INVALID_SOCKET)
    {
        WSACleanup();
        return 1;
    }

    sockaddr_in server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = 0;

    if (bind(sock, (sockaddr*)&server, sizeof(server)) {
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    char recvBuf[1024];
    sockaddr_in from;
    int fromLen = sizeof(from);

    while (true) {
        int bytes = recvfrom(sock, recvBuf, sizeof(recvBuf), 0, (sockaddr *)&from, &fromLen);
        if (bytes == SOCKET_ERROR)
        {
            continue;
        }

        IPHEADER *iph = (IPHEADER *)recvBuf;
        int iphLen = (iph->ip_verlen & 0x0F) * 4;

        if (iph->ip_proto != IPPROTO_ICMP)
        {
            continue;
        }

        ICMPHEADER *icmph = (ICMPHEADER *)(recvBuf + iphLen);

        if (icmph->type == 13)
        {
            auto now = std::chrono::system_clock::now();
            auto duration = now.time_since_epoch();
            auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();

            char sendBuf[sizeof(ICMPHEADER) + 12];
            ICMPHEADER *reply = (ICMPHEADER *)sendBuf;
            reply->type = 14;
            reply->code = 0;
            reply->checksum = 0;
            reply->id = icmph->id;
            reply->seq = icmph->seq;

            uint32_t *timestamps = (uint32_t *)(sendBuf + sizeof(ICMPHEADER));
            timestamps[0] = htonl(millis);
            timestamps[1] = htonl(millis + 10);
            timestamps[2] = htonl(millis + 20);

            reply->checksum = checksum(sendBuf, sizeof(ICMPHEADER) + 12);

            sendto(sock, sendBuf, sizeof(ICMPHEADER) + 12, 0, (sockaddr *)&from, fromLen);
        }
    }

    closesocket(sock);
    WSACleanup();
    return 0;
}